'''
modus 串口
'''
import threading
import time
import traceback

import modbus_tk.defines as cst
import modbus_tk.modbus_rtu as modbus_rtu
import serial
try:
    from plc_client.layer1.abc_client import PLCClientInterface
except:
    from abc_client import PLCClientInterface
# 绝对地址通讯； 标签通讯方式


class MDSRtuClient(PLCClientInterface):

    def __init__(self, ip='127.0.0.1'):
        # 创建通讯客户端实例
        # 创建 Modbus RTU 主站
        self.master = modbus_rtu.RtuMaster(
            serial.Serial(
                port=ip,
                baudrate=19200,  # 根据 PLC 设置调整
                bytesize=8,
                parity='N',
                stopbits=2,
                xonxoff=0
            )
        )

        # 设置超时时间
        self.master.set_timeout(5.0)

        self.lock = threading.Lock() # 同步
    def connect(self):
        # 连接至PLC
        # is_ok = False
        # t = time.time()
        # while not is_ok:
        #     is_ok = self.connect_once()
        #     if time.time()-t > 15: # 10s
        #         break
        #     time.sleep(1)
        # if not is_ok:
        #         raise Exception('plc 连接失败')
        #
        pass


    def connect_once(self):
        # 连接至PLC
        # try:
        #     self.lock.acquire()
        #     self.client.connect(self.ip, 0, 0, self.port)  # 请求大小为480B的pdu
        #     print('plc 连接成功')
        #     self.lock.release()
        #     return True
        # except Exception as e:
        #     self.lock.release()
        #     print(traceback.format_exc())
        #     return False
        #     # raise BaseException('plc 连接失败')
        pass
    def get_connected(self):
        return self.client.get_connected()

    def read_int8(self, start=0, size=1) -> int:
        return self.read_int16(start)


    def read_int16(self, start=0) -> int:  # 读int16
        # dbnumber, start = address
        # try:
        #     self.lock.acquire()
        #     buffer = self.client.read_area(snap7.types.Areas.DB, start[0], start[1], size) # buffer为bytearray
        #     self.lock.release()
        #     value_int16 = util.get_int(buffer,0) # 解码为整数
        #     return value_int16
        # except:
        #     self.lock.release()
        #     raise Exception('read_int16 错误 start {start}')
        try:
            self.lock.acquire()
            response = self.master.execute(
                1,  # 从站地址（Slave ID）
                cst.READ_HOLDING_REGISTERS,  # 功能码（Function Code）
                start,  # 起始寄存器地址（Starting Address）
                1  # 读取的寄存器数量（Quantity） 每个寄存器16位，这里读1个寄存器（即1个int16）。
            )
            self.lock.release()
            value_int16 = response[0] # (123)
            print(f"成功读取 INT16 值 {value_int16} 从地址 {start}")
            return value_int16
        except:
            self.lock.release()
            print(f'plc 地址{start}')
            print(traceback.format_exc())
            raise Exception()


    def read_int32(self, start=(128,0), size=4) -> int:  # 读int16
        # dbnumber, start = address
        # try:
        #     self.lock.acquire()
        #     buffer = self.client.read_area(snap7.types.Areas.DB, start[0], start[1], size) # buffer为bytearray
        #     self.lock.release()
        #     value_int32 = util.get_dint(buffer,0) # 解码为整数
        #     return value_int32
        # except:
        #     self.lock.release()
        #     raise Exception('read_int32 错误 start {start}')

        pass

    def read_int32s(self, start=(128,0), numbs=1) -> int:  # 读int16
        # dbnumber, start = address
        # try:
        #     self.lock.acquire()
        #     buffer = self.client.read_area(snap7.types.Areas.DB, start[0], start[1], numbs*4) # buffer为bytearray
        #     self.lock.release()
        #     value_int32s = []
        #     for i in range(numbs):
        #         value_int32 = util.get_dint(buffer,4*i) # 解码为整数
        #         value_int32s.append(value_int32)
        #     return value_int32s
        # except:
        #     self.lock.release()
        #     raise Exception('read_int32 错误 start {start}')

        pass

    def read_bool(self, start=0, size=1) -> int: # 读bool
        # buffer = self.client.read_area(snap7.types.Areas.DB, self.dbnumber, start, size)
        # value_int16 = util.get_bool(buffer, 0, 0)
        # return value_int16

        return 0

    def read_real(self, start=(128,0), size=4) -> float: # 读实数
        # buffer = self.client.read_area(snap7.types.Areas.DB, start[0], start[1], size)
        # value_real = util.get_real(buffer, 0)
        # return value_real

        return 0

    def read_reals(self, start=(128,0), numbs=1) -> int:  # 读int16
        # dbnumber, start = address
        # try:
        #     self.lock.acquire()
        #     buffer = self.client.read_area(snap7.types.Areas.DB, start[0], start[1], numbs*4) # buffer为bytearray
        #     self.lock.release()
        #     value_int32s = []
        #     for i in range(numbs):
        #         value_int32 = util.get_real(buffer,4*i) # 解码为整数
        #         value_int32s.append(value_int32)
        #     return value_int32s
        # except:
        #     self.lock.release()
        #     raise Exception('read_reals 错误 start {start}')

        return 0

    def write_int8(self, start=0, data_int8=0): # 写int8
        # data_bytes = bytearray(1) # 实数4字节
        # util.set_byte(data_bytes, 0, data_int8)
        # self.lock.acquire()
        # self.client.write_area(snap7.types.Areas.DB, self.dbnumber, start, data_bytes)
        # self.lock.release()
        #
        # # 由于 Modbus 通常以 16 位寄存器为单位操作，
        # # 我们需要将 INT8 转换为 INT16 写入
        # # 注意: 有些 PLC 可能需要特殊处理 INT8
        #
        # # 写入单个寄存器 (功能码 6)
        # # 对于 INT8，我们将其作为 INT16 写入
        # response = self.master.execute(
        #     1, # slave_id
        #     cst.WRITE_SINGLE_REGISTER,
        #     start,
        #     output_value=int(data_int8)
        # )
        #
        # print(f"成功写入 INT8 值 {data_int8} 到PLC地址 {start}")
        # return response
        return self.write_int16(start, data_int8)

    def write_int16(self, start=(128,0), data_int16=0): # 写int16
        try:
            self.lock.acquire()
            response = self.master.execute(
                1,  # slave_id
                cst.WRITE_SINGLE_REGISTER,
                start,
                output_value=int(data_int16)
            )
            self.lock.release()
            print(f"成功写入 INT16 值 {data_int16} 到地址 {start}")
            return response
        except:
            self.lock.release()
            print(traceback.format_exc())
            # raise Exception('write_int16 错误')

    def write_real(self, start=(0,0), data_real=1.0): # 写实数  用于发送坐标等
        # data_bytes = bytearray(4) # 实数4字节
        # util.set_real(data_bytes, 0, data_real)
        # self.client.write_area(snap7.types.Areas.DB, start[0], start[1], data_bytes)
        pass

    def write_bool(self, start=0, data_bool=False): # 写bool
        # data_bytes = bytearray(1)  #
        # util.set_bool(data_bytes, 0, 0, data_bool)
        # self.client.write_area(snap7.types.Areas.DB, self.dbnumber, start, data_bytes)
        pass


    def read_string(self, start=0, size=50, dbnumber=0) -> str: # 读 string  size=256
        # buffer = self.client.read_area(snap7.types.Areas.DB, dbnumber, start, size)
        # value_str = util.get_string(buffer, 0)
        # return value_str
        return 0

    def write_string(self, start=0, data_str='hello', dbnumber=0): # write string
        # data_bytes = bytearray(255) #  ？
        # util.set_string(data_bytes, 0, data_str)
        # print(data_bytes)
        # le = min(len(data_str)+2,50)
        # print(data_bytes[:le])
        # self.client.write_area(snap7.types.Areas.DB, dbnumber, start, data_bytes[:le]) #size 50
        return 0


    def close(self):
        # self.lock.acquire()
        # self.client.disconnect()
        # self.lock.release()
        # print(f"plc 连接状态：{self.client.get_connected()}")
        print('plc close')




def test_s7client():

    # 建立客户端
    cl = MDSRtuClient('COM1')
    # cl = S7Client()
    cl.connect()
    # cl2 = S7Client('192.168.0.1',  102)
    # # cl = S7Client()
    # cl2.connect()

    # data = cl.read_bool(start=80.1)
    # cl.write_bool(start=96,data_bool=True)

    cl.write_int16(start=0,data_int16=45330)
    # cl.write_real(start=(49, 0),data_real=10.22)
    # data = cl.read_reals(start=(49,0), numbs=16*6)

    res = cl.read_int16(start=0)
    print(res)
    # print(data)
    cl.close()



if __name__ == "__main__":
    test_s7client()
    # tests7()